home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2001 December / pcwk12201b.iso / Wersje pelne i specjalne / Winamp 2.77 i 3.0beta / wasabi-sdk_beta1.exe / studio / common / region.cpp < prev    next >
C/C++ Source or Header  |  2001-10-08  |  11KB  |  385 lines

  1. /*
  2.  
  3.   Nullsoft WASABI Source File License
  4.  
  5.   Copyright 1999-2001 Nullsoft, Inc.
  6.  
  7.     This software is provided 'as-is', without any express or implied
  8.     warranty.  In no event will the authors be held liable for any damages
  9.     arising from the use of this software.
  10.  
  11.     Permission is granted to anyone to use this software for any purpose,
  12.     including commercial applications, and to alter it and redistribute it
  13.     freely, subject to the following restrictions:
  14.  
  15.     1. The origin of this software must not be misrepresented; you must not
  16.        claim that you wrote the original software. If you use this software
  17.        in a product, an acknowledgment in the product documentation would be
  18.        appreciated but is not required.
  19.     2. Altered source versions must be plainly marked as such, and must not be
  20.        misrepresented as being the original software.
  21.     3. This notice may not be removed or altered from any source distribution.
  22.  
  23.  
  24.   Brennan Underwood
  25.   brennan@nullsoft.com
  26.  
  27. */
  28.  
  29. #include <windows.h>
  30. #include "region.h"
  31.  
  32. #include "canvas.h"
  33. #include "basewnd.h"
  34.  
  35. Region::Region() {
  36.     hrgn = CreateRectRgn(0,0,0,0);
  37. }
  38.  
  39. Region::Region(RECT *r) {
  40.     hrgn = CreateRectRgn(r->left,r->top,r->right,r->bottom);
  41. }
  42.  
  43. Region::Region(int l, int t, int r, int b) {
  44.     hrgn = CreateRectRgn(l,t,r,b);
  45. }
  46.  
  47. Region::Region(HRGN r) {
  48.   HRGN R = CreateRectRgn(0, 0, 0,0);
  49.   CombineRgn(R, r, r, RGN_COPY);
  50.   hrgn = R;
  51. }
  52.  
  53. Region::Region(Canvas *c) {
  54.     hrgn = CreateRectRgn(0,0,0,0);
  55.     GetClipRgn(c->getHDC(), hrgn);
  56. }
  57.  
  58. Region::~Region() {
  59.     if (hrgn)
  60.         DeleteObject(hrgn);
  61.  
  62. Region *Region::clone() {
  63.   Region *newregion = new Region(getHRGN());
  64.   return newregion;
  65. }
  66.  
  67. void Region::disposeClone(Region *r) {
  68.   delete r; // todo: validate pointer before deleting
  69. }
  70.  
  71. // returns a handle that SetWindowRgn understands (non portable). We should NOT delete this handle, windows will delete 
  72. // it by itself upon setting a new region of destroying the window
  73. HRGN Region::makeWindowRegion() {
  74.   HRGN R = CreateRectRgn(0, 0, 0,0);
  75.   CombineRgn(R, hrgn, hrgn, RGN_COPY);
  76.   return R;
  77. }
  78.  
  79. Region::Region(SkinBitmap *bitmap, int xoffset, int yoffset, BOOL inverted, int dothreshold, char threshold, int thinverse) {
  80.   hrgn = alphaToRegionRect(bitmap, xoffset, yoffset, FALSE, 0, 0, 0, 0, inverted, dothreshold, threshold, thinverse);
  81. }
  82.  
  83. Region::Region(SkinBitmap *bitmap, int xoffset, int yoffset, int _x, int _y, int _w, int _h, BOOL inverted, int dothreshold, char threshold, int thinverse) {
  84.   hrgn = alphaToRegionRect(bitmap, xoffset, yoffset, TRUE, _x, _y, _w, _h, inverted, dothreshold, threshold, thinverse);
  85. }
  86.  
  87. HRGN Region::alphaToRegionRect(SkinBitmap *bitmap, int xoffset, int yoffset, BOOL portion, int _x, int _y, int _w, int _h, BOOL inverted, int dothreshold, unsigned char threshold, int thinverse) {
  88.  
  89.     HRGN hRgn = NULL;
  90.   int bmWidth=bitmap->getWidth();
  91.   int bmHeight=bitmap->getHeight();
  92.   int fullw=bitmap->getFullWidth();
  93.  
  94.   void *pbits32=bitmap->getBits();
  95.   if (!pbits32) return NULL;
  96.  
  97.     RGNDATA *pData;
  98.     int y, x;
  99.  
  100.     // For better performances, we will use the ExtCreateRegion() function to create the
  101.     // region. This function take a RGNDATA structure on entry. We will add rectangles by
  102.     // amount of ALLOC_UNIT number in this structure.
  103.   // JF> rects are 8 bytes, so this allocates just under 16kb of memory, no need to REALLOC
  104.     #define MAXRECTS 2000
  105.     pData = (RGNDATA *)MALLOC(sizeof(RGNDATAHEADER) + (sizeof(RECT) * MAXRECTS));
  106.   if (!pData) return NULL;
  107.  
  108.     pData->rdh.dwSize = sizeof(RGNDATAHEADER);
  109.     pData->rdh.iType = RDH_RECTANGLES;
  110.     pData->rdh.nCount = pData->rdh.nRgnSize = 0;
  111.  
  112.   SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
  113.  
  114.   int x_end=(portion ? _w+_x-bitmap->getX() : bmWidth);
  115.   int y_end=(portion ? _h+_y-bitmap->getY() : bmHeight);
  116.   int x_start=(portion ? _x-bitmap->getX() : 0);
  117.   int y_start=(portion ? _y-bitmap->getY() : 0);
  118.  
  119.   unsigned int iv=inverted?0xff000000:0;
  120.  
  121.   int xo=bitmap->getX();
  122.   int yo=bitmap->getY();
  123.     for (y = y_start; y < y_end; y++) {
  124.         // Scan each bitmap pixel from left to right
  125.     unsigned int *lineptr=((unsigned int *)pbits32) + fullw*(y+yo) + xo;
  126.         for (x = x_start; x < x_end; x++) {
  127.             // Search for a continuous range of "non transparent pixels"
  128.             int x0 = x;
  129.         unsigned int *p = lineptr;
  130.       if (dothreshold) {
  131.         if (thinverse) {
  132.                   while (x < x_end) {
  133.             unsigned int a=p[x];
  134.                       if ((a&0xff000000) == iv || 
  135.                 (((((a & 0xFF) > threshold || ((a & 0xFF00) >> 8) > threshold || ((a & 0xFF0000) >> 16) > threshold)))))
  136.                                   break;
  137.                       x++;
  138.                   }
  139.         }
  140.         else {
  141.                   while (x < x_end) {
  142.             unsigned int a=p[x];
  143.                       if ((a&0xff000000) == iv || 
  144.                 (((((a & 0xFF) < threshold || ((a & 0xFF00) >> 8) < threshold || ((a & 0xFF0000) >> 16) < threshold)))))
  145.                                   break;
  146.                       x++;
  147.                   }
  148.         }
  149.       }
  150.       else {
  151.               while (x < x_end) {
  152.                   if ((p[x] & 0xFF000000) == iv) break;
  153.           x++;
  154.         }
  155.       }
  156.  
  157.             if (x > x0) {
  158.                 SetRect(((RECT *)&pData->Buffer) + pData->rdh.nCount, x0, y, x, y+1);
  159.  
  160.         pData->rdh.nCount++;
  161.  
  162.                 if (x0 < pData->rdh.rcBound.left) pData->rdh.rcBound.left = x0;
  163.                 if (y < pData->rdh.rcBound.top) pData->rdh.rcBound.top = y;
  164.                 if (x > pData->rdh.rcBound.right) pData->rdh.rcBound.right = x;
  165.                 if (y >= pData->rdh.rcBound.bottom) pData->rdh.rcBound.bottom = y+1;
  166.  
  167.                 // On Windows98, ExtCreateRegion() may fail if the number of rectangles is too
  168.                 // large (ie: > 4000). Therefore, we have to create the region by multiple steps.
  169.                 if (pData->rdh.nCount == MAXRECTS) {
  170.                     HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
  171.                     if (hRgn) {
  172.                         CombineRgn(hRgn, hRgn, h, RGN_OR);
  173.                         DeleteObject(h);
  174.                     }
  175.                     else hRgn = h;
  176.                     pData->rdh.nCount = 0;
  177.                     SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
  178.                 }
  179.             }
  180.         }
  181.     }
  182.  
  183.     // Create or extend the region with the remaining rectangles
  184.     HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
  185.     if (hRgn)
  186.     {
  187.         CombineRgn(hRgn, hRgn, h, RGN_OR);
  188.         DeleteObject(h);
  189.     }
  190.     else
  191.         hRgn = h;
  192.  
  193.     // Clean up
  194.     FREE(pData);
  195.  
  196.   if (hRgn && (xoffset || yoffset))
  197.     OffsetRgn(hRgn, xoffset, yoffset);
  198.  
  199.  
  200.     return hRgn;
  201. }
  202.  
  203. BOOL Region::ptInRegion(POINT *pt) {
  204.   ASSERT(hrgn != NULL);
  205.   return PtInRegion(hrgn, pt->x, pt->y);
  206. }
  207.  
  208. void Region::offset(int x, int y) {
  209.   ASSERT(hrgn != NULL);
  210.   OffsetRgn(hrgn, x, y);
  211. }
  212.  
  213. void Region::getBox(RECT *r) {
  214.   GetRgnBox(hrgn, r);
  215. }
  216.  
  217. HRGN Region::getHRGN() {
  218.   return hrgn;
  219. }
  220.  
  221. void Region::subtract(RECT *r) {
  222.   Region *s = new Region(r);
  223.   subtract(s);
  224.   delete s;
  225. }
  226.  
  227. void Region::subtract(Region *reg) {
  228.   CombineRgn(hrgn, hrgn, reg->getHRGN(), RGN_DIFF);
  229. }
  230.  
  231. void Region::and(Region *reg) {
  232.   CombineRgn(hrgn, hrgn, reg->getHRGN(), RGN_AND);
  233. }
  234.  
  235. void Region::addRect(RECT *r) {
  236.   Region *a = new Region(r);
  237.   add(a);
  238.   delete a;
  239. }
  240.  
  241. void Region::add(Region *reg) {
  242.   ASSERT(reg != NULL);
  243.   CombineRgn(hrgn, hrgn, reg->getHRGN(), RGN_OR);
  244. }
  245.  
  246. int Region::isEmpty() {
  247.   RECT r;
  248.   getBox(&r);
  249.   if (r.left == r.right && r.bottom == r.top) return 1;
  250.   return 0;
  251. }
  252.  
  253. int Region::enclosed(Region *r) {
  254.   HRGN h = CreateRectRgn(0,0,0,0);
  255.   int rs = CombineRgn(h, hrgn, r->getHRGN(), RGN_DIFF);
  256.   DeleteObject(h);
  257.   return rs == NULLREGION;
  258. }
  259.  
  260. int Region::enclosed(Region *r, Region *outside) {
  261.   int rs = CombineRgn(outside->getHRGN(), hrgn, r->getHRGN(), RGN_DIFF);
  262.   return rs == NULLREGION;
  263. }
  264.  
  265. #define IntersectRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_AND)
  266.  
  267. int Region::intersects(Region *r) {
  268.   ASSERT(r != NULL);
  269.   HRGN res = CreateRectRgn(0,0,0,0);
  270.   int rs = IntersectRgn(res, hrgn, r->getHRGN());
  271.   DeleteObject(res);
  272.   return (rs != NULLREGION && rs != ERROR);
  273. }
  274.  
  275. int Region::intersects(Region *r, Region *intersection) {
  276.   ASSERT(r != NULL);
  277.   ASSERT(intersection != NULL);
  278.   int rs = IntersectRgn(intersection->getHRGN(), hrgn, r->getHRGN());
  279.   return (rs != NULLREGION && rs != ERROR);
  280. }
  281.  
  282. int Region::intersects(RECT *r) {
  283.   return RectInRegion(hrgn, r);
  284. }
  285.  
  286. int Region::intersects(RECT *r, Region *intersection) {
  287.   Region *rect = new Region(r);
  288.   int res = intersects(rect, intersection);
  289.   delete rect;
  290.   return res;
  291. }
  292.  
  293. void Region::getRgnBox(RECT *r) {
  294.   ASSERT(r != NULL);
  295.   GetRgnBox(hrgn, r);
  296. }
  297.  
  298. void Region::empty() {
  299.   ASSERT(hrgn != NULL);
  300.   DeleteObject(hrgn);
  301.   hrgn = CreateRectRgn(0,0,0,0);
  302.   ASSERT(hrgn != NULL);
  303. }
  304.  
  305. void Region::setRect(RECT *r) {
  306.   ASSERT(hrgn != NULL);
  307.   SetRectRgn(hrgn, r->left, r->top, r->right, r->bottom);
  308. }
  309.  
  310. int Region::equals(Region *r) {
  311.   ASSERT(r);
  312.   Region *cl = r->clone();
  313.   cl->subtract(this);
  314.   int ret = cl->isEmpty();
  315.   r->disposeClone(cl);
  316.   cl = clone();
  317.   cl->subtract(r);
  318.   ret &= cl->isEmpty();
  319.   disposeClone(cl);
  320.   return ret;
  321. }
  322.  
  323. int Region::isRect() {
  324.   RECT r;
  325.   getBox(&r);
  326.   Region *n = new Region(&r);
  327.   ASSERT(n != NULL);
  328.   if (equals(n)) {
  329.     delete n;
  330.     return 1;
  331.   }
  332.   delete n;
  333.   return 0;
  334. }
  335.  
  336. void Region::scale(double s, BOOL round) {
  337.   scale(s, s, round);
  338. }
  339.  
  340. void Region::scale(double sx, double sy, BOOL round) {
  341.   ASSERT(hrgn != NULL);
  342.   DWORD size=0;
  343.   size = GetRegionData(hrgn, size, NULL); 
  344.   if (!size) return;
  345.   DWORD res;
  346.   RGNDATA *data = (RGNDATA *)MALLOC(size);
  347.   RECT *r = (RECT *)data->Buffer;
  348.  
  349.   res = GetRegionData(hrgn, size, (RGNDATA *)data);
  350.   double adj = round?0.99999:0.0;
  351.   int iadj = round?1:0;
  352.  
  353.   if (data->rdh.nCount == 1) {
  354.     RECT nr = data->rdh.rcBound;
  355.     nr.left = (int)((double)(nr.left-iadj) * sx);
  356.     nr.top = (int)((double)(nr.top-iadj) * sy);
  357.     nr.right = (int)((double)nr.right * sx + adj);
  358.     nr.bottom = (int)((double)nr.bottom * sy + adj);
  359.     setRect(&nr);
  360.     FREE(data);
  361.     return;
  362.   }
  363.  
  364.   for (int i=0;i<(int)data->rdh.nCount;i++) {
  365.     r[i].left = (int)((double)(r[i].left-iadj) * sx);
  366.     r[i].top = (int)((double)(r[i].top-iadj) * sy);
  367.     r[i].right = (int)((double)r[i].right * sx + adj);
  368.     r[i].bottom = (int)((double)r[i].bottom * sy + adj);
  369.   }
  370.  
  371.   HRGN nhrgn = ExtCreateRegion(NULL, size, data);
  372.   ASSERTPR(nhrgn != NULL, StringPrintf("size : %s", size));
  373.   FREE(data);
  374.   DeleteObject(hrgn);
  375.   hrgn = nhrgn;
  376. }
  377.  
  378. void Region::debug() {
  379.   HDC d = GetDC(NULL);
  380.   InvertRgn(d, getHRGN());
  381.   Sleep(1000);
  382.   InvertRgn(d, getHRGN());
  383. }
  384.